package com.example.apidocserver.infrastructure.aop;

import com.example.apidocserver.infrastructure.base.BaseEntity;
import com.example.apidocserver.infrastructure.util.user.CurrentUser;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Date;
import java.util.Objects;

/**
 * 权限切面
 *
 * @author xyqlg
 */
@Aspect
@Component
@Slf4j
public class UpsertAop {
    @Pointcut("@annotation(com.example.apidocserver.infrastructure.aop.UpsertAnno)")
    public void action() {
    }

    @Before("action()")
    public void around(JoinPoint joinPoint) {
        UpsertAnno upsertAnno = getUpsertAnno(joinPoint);
        String annotationValue = upsertAnno.value();
        Object[] methodArgs = joinPoint.getArgs();

        if (methodArgs.length == 0) {
            return;
        }

        if ("".equals(annotationValue) || methodArgs.length == 1) {
            setUpsert(methodArgs[0], upsertAnno.isInsert(), upsertAnno.upsert());
        }
    }

    private static UpsertAnno getUpsertAnno(JoinPoint joinPoint) {
        MethodSignature sign = (MethodSignature) joinPoint.getSignature();
        Method method = sign.getMethod();
        return method.getAnnotation(UpsertAnno.class);
    }

    private void setUpsert(Object methodArg, boolean insert, boolean upsert) {
        try {
            if (methodArg instanceof Collection) {
                for (Object obj : (Collection) methodArg) {
                    setUserAndTime(obj, insert, upsert);
                }

            } else {
                setUserAndTime(methodArg, insert, upsert);
            }
        } catch (Exception e) {
            log.error("更新通用设置失败");
        }
    }

    private static void setUserAndTime(Object methodArg, boolean insert, boolean upsert) {
        if (methodArg instanceof BaseEntity) {
            Date now = new Date();
            Integer userId = Math.toIntExact(CurrentUser.getUser().getUserId());
            BaseEntity entity = ((BaseEntity) methodArg);
            if (insert) {
                if (upsert) {
                    if (Objects.isNull(entity.getCreateTime())) {
                        entity.setCreateTime(now);
                    }
                    if (Objects.isNull(entity.getCreator())) {
                        entity.setCreator(userId);
                    }
                } else {
                    entity.setCreateTime(now).setCreator(userId);
                }
            }
            entity.setUpdateTime(now).setUpdater(userId);
        }
    }
}